home *** CD-ROM | disk | FTP | other *** search
- /*
- * locks.c
- * Definitions some derived synchro classes
- *
- */
-
-
- #define _LOCKS_C
-
- #include "presto.h"
- #include "locks.h"
-
-
-
- Lock::Lock(char *name=0) : (OBJ_LOCK, name)
- {
- lo_owner = 0;
- }
-
- Lock::Lock(char *name, int locktype) : (locktype, name)
- {
- lo_owner = 0;
- }
-
-
- Lock::~Lock()
- {
- if (lo_owner)
- error("Can't delete a held lock!");
- }
-
-
-
- //
- // Threads are given ownership of the lock on ENTRY iff there
- // is no current owner. On EXIT, we just clear the owner field
- // and wakeup the first guy on the queue.
- // Inline version falls through to lock if the lock is already
- // held. This optimizes entry for non-occupied routines.
- //
- void
- Lock::lock()
- {
- SynchroObject::lock();
- if (lo_owner == 0) {
- lo_owner = thisthread;
- SynchroObject::unlock();
- } else
- lock2();
- }
-
-
- void
- Lock::unlock()
- {
- SynchroObject::lock();
- if (thisthread != lo_owner)
- error("Can't release someone else's lock");
-
- lo_owner = 0;
- Thread *newowner = recall(); // find new lock owner
- //
- // Dont guarantee fairness
- //
- SynchroObject::unlock();
- if (newowner)
- newowner->wakeup((SynchroObject*)this);
- }
-
-
-
- //
- // Secondary looping entry point for a lock
- //
- void
- Lock::lock2()
- {
- if (thisthread->flags()&TF_SCHEDULER)
- error("Can't block a scheduler thread!");
-
- // expect lock to be held on the way in
- for (;;) {
- if (lo_owner == 0)
- break;
- remember(thisthread);
- SynchroObject::unlock();
- thisthread->sleep(this);
- SynchroObject::lock();
- }
- lo_owner = thisthread;
- SynchroObject::unlock();
- }
-
- void
- Lock::print(ostream& s)
- {
- s << "Lock:";
- SynchroObject::print(s);
- s << form(" lo_owner=0x%x", lo_owner);
- }
-
-
- Monitor::Monitor(char* name=0) : (name, OBJ_MONITOR)
- {
- }
-
- Monitor::~Monitor()
- {
- if (owner())
- error("can't delete a held monitor");
- }
-
- void
- Monitor::print(ostream& s)
- {
- s << "Monitor:";
- Lock::print(s);
- }
-
-
- //
- // Condition variables are bound to monitors. If you run a condition
- // variable UNBOUND, and you do not guarantee that operations on the
- // condition variable are atomic (locked), bad things will happen.
- // Condition variables assume that they will only be referenced
- // from within a monitor, so they don't bother to lock their data
- // structures when referenced.
- //
-
- Condition::Condition(char *name=0) : (OBJ_CONDVAR, name)
- {
- cerr << "Warning: use of unbound condition variable " << name <<
- " is not advised\n";
- co_monitor = 0;
- }
-
- Condition::Condition(Monitor* boundmon) : (OBJ_CONDVAR,0)
- {
- co_monitor = boundmon;
- }
-
- Condition::Condition(Monitor &boundmon) : (OBJ_CONDVAR, 0)
- {
- co_monitor = &boundmon;
- }
-
- Condition::Condition(Monitor* boundmon, char* name) : (OBJ_CONDVAR,name)
- {
- co_monitor = boundmon;
- }
-
- Condition::Condition(Monitor& boundmon, char* name) : (OBJ_CONDVAR, name)
- {
- co_monitor = &boundmon;
- }
-
-
- Condition::~Condition()
- {
- }
-
-
- //
- // Signal a condition variable. Backlogs probably will not get
- // implemented because they may have nasty overtones.
- // No locking needed since we assume we are inside monitored region
- //
- void
- Condition::broadcast()
- {
- Thread *t;
-
- if (!threadok())
- error("Condition broadcast by non-owning thread!");
-
- while (t = waitingQueue()->get()) { // DO NOT LOCK
- t->wakeup(this);
- }
- }
-
- //
- // No locking here either
- //
- void
- Condition::signal()
- {
- if (!threadok())
- error("Condition signal by non-owning thread!");
- Thread *t = waitingQueue()->get(); // DO NOT LOCK
- if (t)
- t->wakeup(this);
- }
-
- //
- // Put a thread to sleep on a condition variable.
- // Get the monitor which we currently hold and exit it.
- //
- // We must be responsible for remembering threads which need to
- // be reawoken on an event of this condition. If we relied on
- // the sleep routines, it is possible that we could wakeup someone
- // up, have them start running, and signal us, yet we have not been
- // remembered since our sleep call hadn't yet gotten far enough.
- //
- // No locking here also
- //
- void
- Condition::wait()
- {
- if (!threadok())
- error("Condition wait by non-owning thread!");
- remember(thisthread); // will NOT lock the queue
- if (co_monitor) { // release the monitor
- co_monitor->exit();
- }
- thisthread->sleep(this);
-
- // reaquire the monitor if we gave it up
- if (co_monitor) {
- co_monitor->entry();
- }
- }
-
-
-
- void
- Condition::print(ostream& s)
- {
- s << "Condition:";
- SynchroObject::print(s);
- s << " bound ";
- if (co_monitor)
- s << co_monitor;
- else
- s << "_unbound_";
- }
-
-
-